﻿///////////////////////////////////////////////////////////////////////////////
//
// This file is part of the BassDrop project
//   https://code.google.com/p/bass-drop/
//
//
// Creator:	Gergely Krajcsovszki (krajcsovszkig@hotmail.com)
// Date:	2014-03-22 13:00
//
//
// Copyright © 2013-2014. Gergely Krajcsovszki
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using BassDrop.Core.Common;
using BassDrop.Core.Common.Cloud;
using BassDrop.Core.Common.General.Events;
using BassDrop.Core.Common.Localization;
using BassDrop.DesktopClient.Utilities;

namespace BassDrop.DesktopClient.UI.Controls
{
	/// <summary>
	/// Interaction logic for CloudStatusControl.xaml
	/// </summary>
	public partial class CloudStatusControl : UserControl
	{
		private List<Exception> m_errors = new List<Exception>();
		private DateTime m_lastUpdated = DateTime.Now;
		private bool m_synchronizing = false;

		public CloudStatusControl()
		{
			InitializeComponent();

			if ( Controller.Instance == null ) // fixes designer errors
			{
				return;
			}

			BindClouds();
			LayoutAll();

			Strings.StaticPropertyChanged += Strings_StaticPropertyChanged;
		}

		/// <summary>
		/// Bind handlers to the events of the cloud manager instance
		/// </summary>
		private void BindClouds()
		{
			CloudManager.Instance.RunningStarted += Instance_RunningStarted;
			CloudManager.Instance.RunningStopped += Instance_RunningStopped;
			CloudManager.Instance.ErrorOccured += Instance_ErrorOccured;
			Controller.Instance.PluginManager.PluginsChanged += PluginManager_PluginsChanged;
			m_synchronizing = CloudManager.Instance.Running;
		}

		/// <summary>
		/// Layout all the components of the context menu and the update the icon
		/// </summary>
		private void LayoutAll()
		{
			LayoutErrors();
			LayoutClouds();
			UpdateIcon();
		}

		/// <summary>
		/// Update the icon (updating / error / idle)
		/// </summary>
		private void UpdateIcon()
		{
			Dispatcher.BeginInvoke( (Action) (() =>
			{
				// TODO: UpdateIcon()
				/*
				 * animációk!
				 * 
				 * sync - forgó nyíl
				 * sync, error - 1,5 mp sync, 0,5 mp error
				 * error - valami warning jel
				 * idle - pipa
				 */
				if ( m_synchronizing )
				{
					if ( m_errors.Count > 0 )
					{
						// Syncing, errors
						imageIcon.Source =
							new ImageSourceConverter().ConvertFrom(
								new Uri( "pack://application:,,,/BassDrop.DesktopClient;component/UI/Images/media-repeat.png" ) ) as ImageSource; // TODO: váltogassa
					}
					else
					{
						// Syncing
						imageIcon.Source =
							new ImageSourceConverter().ConvertFrom(
								new Uri( "pack://application:,,,/BassDrop.DesktopClient;component/UI/Images/media-repeat.png" ) ) as ImageSource; // TODO: forogjon
					}
				}
				else
				{
					if ( m_errors.Count > 0 )
					{
						// Idle, errors
						imageIcon.Source =
							new ImageSourceConverter().ConvertFrom(
								new Uri( "pack://application:,,,/BassDrop.DesktopClient;component/UI/Images/alert.png" ) ) as ImageSource;
					}
					else
					{
						// Idle
						imageIcon.Source =
							new ImageSourceConverter().ConvertFrom(
								new Uri( "pack://application:,,,/BassDrop.DesktopClient;component/UI/Images/check.png" ) ) as ImageSource;
					}
				}
			}), null );
		}

		/// <summary>
		/// Layout the finish time of the last update into the context menu
		/// </summary>
		private void LayoutLastUpdate()
		{
			Dispatcher.BeginInvoke( (Action) (() =>
			{
				menuItemLastUpdated.Header = string.Format( Strings.LabelCloudStatusControlMenuItemLastUpdatedFormat, DateTime.Now - m_lastUpdated );
			}), null );
		}

		/// <summary>
		/// Layout the list of errors occured while syncing into the context menu
		/// </summary>
		private void LayoutErrors()
		{
			Dispatcher.BeginInvoke( (Action) (() =>
			{
				menuItemErrors.Items.Clear();

				foreach ( var item in m_errors )
				{
					MenuItem menuItem = new MenuItem();

					string message = item.ToString();
					if ( message.Length > 50 )
					{
						int cutIndex = message.LastIndexOf( ' ', 47 );

						if ( cutIndex <= 0 )
						{
							cutIndex = 47;
						}

						message = message.Substring( 0, cutIndex ) + "...";
					}

					menuItem.Header = message;
					menuItem.ToolTip = item.ToString();
					menuItem.Click += async ( sender, e ) =>
						{
							await item.Prompt( App.Instance.MainWindow );
							m_errors.Remove( item );
							LayoutErrors();
							UpdateIcon();
						};

					menuItemErrors.Items.Add( menuItem );
				}

				if ( menuItemErrors.HasItems )
				{
					menuItemErrors.Items.Add( new Separator() );
					menuItemErrors.Items.Add( menuItemDismissErrors );
					menuItemErrors.IsEnabled = true;
				}
				else
				{
					menuItemErrors.IsEnabled = false;
				}
			}), null );
		}

		/// <summary>
		/// Layout the list of active cloud accounts into the context menu
		/// </summary>
		private void LayoutClouds()
		{
			Dispatcher.BeginInvoke( (Action) (async () =>
			{
				// need to build up the list separately, otherwise the await might mess things up
				List<MenuItem> items = new List<MenuItem>();

				foreach ( var item in Controller.Instance.PluginManager.GetCloudProviders() )
				{
					foreach ( var instance in item.GetInstances() )
					{
						if ( ((CloudConnectionBase) instance).IsAvailable )
						{
							MenuItem menuItem = new MenuItem();

							menuItem.Header = instance.InstanceName + (((CloudConnectionBase) instance).IsDefault ? " (" + Strings.WordDefault + ")" : "");

							try
							{
								AccountInfo accountInfo = await ((CloudConnectionBase) instance).GetAccountInfo();
								menuItem.Header += " (" + accountInfo.UserName + " - " + accountInfo.UserEmail + ")";
								menuItem.ToolTip = string.Format( Strings.LabelCloudStatusControlAccountInfoTooltipFormat,
									accountInfo.FreeBytes / 1073741824.0,
									accountInfo.UsedBytes / 1073741824.0,
									accountInfo.UsedPercent,
									accountInfo.QuotaBytes / 1073741824.0 );
							}
							catch ( Exception )
							{
								// Probably a network issue prevents getting the account info, ignore
							}

							menuItem.Click += ( sender, e ) =>
							{
								((MainWindow) App.Instance.MainWindow).ShowSettingsFor( instance );
							};

							items.Add( menuItem );
						}
					}
				}

				menuItemClouds.Items.Clear();

				foreach ( var item in items )
				{
					menuItemClouds.Items.Add( item );
				}

				menuItemSynchronize.IsEnabled = menuItemClouds.IsEnabled = menuItemClouds.HasItems;
			}), null );
		}

		private void Strings_StaticPropertyChanged( object sender, System.ComponentModel.PropertyChangedEventArgs e )
		{
			if ( e.PropertyName == "Strings" )
			{
				LayoutAll();
			}
		}

		private void Button_Click( object sender, RoutedEventArgs e )
		{
			contextMenu.PlacementTarget = button;
			contextMenu.IsOpen = true;
		}

		private void Instance_RunningStarted( object sender, EventArgs e )
		{
			m_synchronizing = true;
			UpdateIcon();
		}

		private void Instance_RunningStopped( object sender, EventArgs e )
		{
			m_lastUpdated = DateTime.Now;
			LayoutLastUpdate();
			m_synchronizing = false;
			UpdateIcon();
		}

		private void Instance_ErrorOccured( object sender, CustomDataEventArgs<Exception> e )
		{
			m_errors.Insert( 0, e.Data );
			LayoutErrors();
			UpdateIcon();
		}

		private void menuItemDismissErrors_Click( object sender, RoutedEventArgs e )
		{
			m_errors.Clear();
			LayoutErrors();
			UpdateIcon();
		}

		private void menuItemSynchronize_Click( object sender, RoutedEventArgs e )
		{
			CloudManager.Instance.ScheduleSynchronize();
		}

		private void PluginManager_PluginsChanged( object sender, EventArgs e )
		{
			Dispatcher.BeginInvoke( (Action) (() => LayoutClouds()) );
		}

		private void menuItemLastUpdated_IsVisibleChanged( object sender, DependencyPropertyChangedEventArgs e )
		{
			LayoutLastUpdate();
		}
	}
}
